package com.hwq.plugin.sample

import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.AdviceAdapter;

public class SampleTimeCostVisitor extends ClassVisitor {
    SampleTimeCostVisitor(int api, ClassVisitor classVisitor) {
        super(api, classVisitor)
    }

    @Override
    MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        def visitor = super.visitMethod(access, name, descriptor, signature, exceptions)
        if (name == '<clinit>' || name == '<init>') {
            return visitor;
        }
        return new AdviceAdapter(Opcodes.ASM5, visitor, access, name, descriptor) {
            private def startTimeLocal = -1; // 保存 startTime 的局部变量索引

            @Override
            void onMethodEnter() {
                // 在onMethodEnter中插入代码 long l = System.currentTimeMillis()
                mv.visitMethodInsn(
                        Opcodes.INVOKESTATIC,
                        "java/lang/System",
                        "currentTimeMillis",
                        "()J",
                        false
                );
                startTimeLocal = newLocal(Type.LONG_TYPE); // 创建一个新的局部变量来保存 startTime
                mv.visitVarInsn(Opcodes.LSTORE, startTimeLocal);
            }

            @Override
            protected void onMethodExit(int opcode) {
                // 在onMethodExit中插入代码 Log.e("HwqTransform", "Method: $name, timecost: " + (System.currentTimeMillis() - startTime))
                mv.visitTypeInsn(
                        Opcodes.NEW,
                        'java/lang/StringBuilder'
                );
                mv.visitInsn(Opcodes.DUP);
                mv.visitLdcInsn('Method:' + name + ', timecost: ');
                mv.visitMethodInsn(
                        Opcodes.INVOKESPECIAL,
                        "java/lang/StringBuilder",
                        "<init>",
                        "(Ljava/lang/String;)V",
                        false
                );
                mv.visitMethodInsn(
                        Opcodes.INVOKESTATIC,
                        "java/lang/System",
                        "currentTimeMillis",
                        "()J",
                        false
                );
                mv.visitVarInsn(Opcodes.LLOAD, startTimeLocal);
                mv.visitInsn(Opcodes.LSUB);
                mv.visitMethodInsn(
                        Opcodes.INVOKEVIRTUAL,
                        "java/lang/StringBuilder",
                        "append",
                        "(J)Ljava/lang/StringBuilder;",
                        false
                );
                mv.visitMethodInsn(
                        Opcodes.INVOKEVIRTUAL,
                        "java/lang/StringBuilder",
                        "toString",
                        "()Ljava/lang/String;",
                        false
                );
                mv.visitLdcInsn("HwqTransform");
                mv.visitInsn(Opcodes.SWAP);
                mv.visitMethodInsn(
                        Opcodes.INVOKESTATIC,
                        "android/util/Log",
                        "e",
                        "(Ljava/lang/String;Ljava/lang/String;)I",
                        false
                );
                mv.visitInsn(POP);
                super.onMethodExit(opcode)
            }
        }
    }
}

